package cn.com.ccxe.core.io;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.ccxe.core.crawl.CrawlContorl;
import cn.com.ccxe.core.util.Configurations;

/**
 * 镜像工具
 * 
 * @author hetao
 * 
 */
public abstract class AbstractMirrorWrite {

	private Logger 				logger = LoggerFactory.getLogger(AbstractMirrorWrite.class);
	private static final int 	BUFFER_SIZE = 4096;
	public static final int 	MAX_DOWNLOAD_SIZE = Configurations.getInt("fetcher.max_download_size", 10240);
	protected static String 	MIRROR_PATH = Configurations.getString("mirror.path","mirror");
	protected static String 	SYSTEM_PATH = CrawlContorl.getContentPath();

	public String getPath(String url) {
		String directory = getDirectoryPath(url);
		String filename = getFileName(url);
		String str = directory + filename;
		return str;
	}
	public String getServerPath(String url) {
		String path = MIRROR_PATH;
		if(url.startsWith("http://")) {
			path = path + url.substring(7);
		}
		return path;
	}
	public String getDirectoryPath(String url) {
		String path = clearUrl(url);
		int lastIndex = path.lastIndexOf("/");
		if(lastIndex == -1) {
			return SYSTEM_PATH+MIRROR_PATH+path;
		}
		return SYSTEM_PATH+MIRROR_PATH+path.substring(0,lastIndex);
	}
	
	public String getFileName(String url) {
		String path = clearUrl(url);
		int lastIndex = path.lastIndexOf("/");
		if(lastIndex <= 0 || lastIndex == (path.length()-1)) {
			return "/index.html";
		}
		return path.substring(lastIndex);
	}
	
	private String clearUrl(String url) {
		if(url.startsWith("http://")) {
			return url.substring(7);
		}
		return url;
	}
	
//	public abstract void writeFile(ByteArrayEntity content, String url)
//			throws IOException;
	public abstract void writeFile(String text, String url ) throws IOException;

	protected void write(String content, File file, String encoding) throws IOException {
		FileUtils.writeStringToFile(file, content,encoding);
	}
	/**
	 * 将数据写到文件中
	 * 
	 * @param context
	 *            数据
	 * @param file
	 *            文件
	 * @throws IOException 
	 * @throws IOException
	 */
	protected void write(byte[] context, File file) throws IOException {
		if(file != null && !file.exists()) {
			try {
				file.createNewFile();
			} catch(IOException e) {
				logger.info("创建网页镜像文件失败!{}\n{}",e.getMessage(),e.getStackTrace());
				throw e;
			}
		}
		FileUtils.writeByteArrayToFile(file, context);
		
//		ByteBuffer buffer = allocateByteBuffer(context.length);
//		FileOutputStream output = null;
//		FileChannel outChannel = null;
//		try {
//			output = new FileOutputStream(file);
//			outChannel = output.getChannel();
//
//			for (int i = 0; i < context.length; ++i) {
//				buffer.put(context[i]);
//			}
//			buffer.flip();
//			outChannel.write(buffer);
//
//		} catch (FileNotFoundException e) {
//			logger.info("文件 " + file.getPath() + "不存在！");
//			logger.error(e);
//		} catch (IOException e) {
//			logger.info("写文件失败！");
//			logger.error(e);
//		} finally {
//			outChannel.close();
//			close(output);
//		}
	}

	/**
	 * 
	 * @param input
	 * @param file
	 * @param totalsize
	 * @throws IOException
	 */
	protected void write(InputStream input, File file ,int totalsize) throws IOException {
		ByteBuffer bBuf = allocateByteBuffer(totalsize);
		FileChannel outChannel = null;
		FileOutputStream output = null;
		final byte[] b = new byte[BUFFER_SIZE];
		
		try {
			int len;
			double finished = 0;
			output = new FileOutputStream(file);
			while ((len = input.read(b)) != -1) {
				if (finished + b.length > bBuf.capacity()) {
					break;
				}
				bBuf.put(b, 0, len);
				finished += len;				
			}
			
			outChannel = output.getChannel();
		    outChannel.write(bBuf);
		} catch (final BufferOverflowException boe) {
			logger.info("Page size exceeds maximum allowed.{}\n{}",boe.getMessage(),boe.getStackTrace());			
		} catch (final IOException e) {
			logger.error("{}\n{}",e.getMessage(),e.getStackTrace());
		} catch (final Exception e) {
			logger.error("{}\n{}",e.getMessage(),e.getStackTrace());
		} finally {
			close(output);
			if(outChannel != null) {
				outChannel.close();
			}
		}
	}
	
	/**
	 * 分配缓冲区
	 * @param totalsize
	 * @return
	 */
	private ByteBuffer allocateByteBuffer(int totalsize) {
		ByteBuffer bBuf;
		if (totalsize > 0) {
			bBuf = ByteBuffer.allocate(totalsize + 1024);
		} else {
			bBuf = ByteBuffer.allocate(MAX_DOWNLOAD_SIZE); 
		}
		return bBuf;
	}
	
	/**
	 * 关闭输出流
	 * @param output
	 *            输入流
	 * @throws IOException
	 *             如果无法关闭。
	 */
	protected void close(OutputStream output) {
		try {
			output.flush();
			output.close();
		} catch (IOException e) {
			logger.info("关闭OutputStream失败！{}\n{}",e.getMessage(),e.getStackTrace());
		}
	}
	
	/**
	 * 创建所需要的所有目录.
	 * 
	 * @throws IOException
	 *             如果需要创建的目录无法创建
	 * @throws IOException
	 *             如果需要创建的目录不可写
	 * @throws IOException
	 *             如果一个非目录的文件存在并与目录具有相同的路径
	 */
	protected void mkdirs(File filePath) throws IOException {
		if (!filePath.exists()) {
			if (!filePath.mkdirs()) {
				throw new IOException("无法创建目录： " + filePath.getAbsolutePath());
			}
		} else if (!filePath.canWrite()) {
			throw new IOException("目录" + filePath.getAbsolutePath() + " 不可写.");
		} else if (!filePath.isDirectory()) {
			throw new IOException("文件 " + filePath.getAbsolutePath()
					+ " 不是一个目录.");
		}
	}
}
